#ifndef SENTENCIASql_H
#define SENTENCIASql_H

#include <QString>
#include <QDateTime>
#include "tablas_global.h"

/**
  * Representa una sentecia Sql.
  * Sirve para construir las sentencias y recuperarlas en forma de cadena de texto.
  */
class TABLAS_EXPORT SentenciaSql
{
public:
    SentenciaSql();    
    SentenciaSql(QString strSql);
    virtual ~SentenciaSql();

protected:
    enum { Nulo, Select, Insert, Update, Delete } m_eComando;

    // Para las selecciones
    QString m_strSelect;
    QString m_strFrom;
    QString m_strWhere;
    QString m_strGroup;
    QString m_strHaving;
    QString m_strOrder;

    // Para los comandos
    QString m_strTabla;
    QString m_strListaCampos;
    QString m_strListaValores;
    QString m_strListaModificaciones;

    QString m_strFind; // Condición de busqueda para encontrar el registro editado

    QString getSelectSql() const;
    QString getInsertSql() const;
    QString getUpdateSql() const;
    QString getDeleteSql() const;

public:
    /**
     * Asigna la cadena de la sentencia SQL
     */
    void setSql (QString strSql);

    /**
     * Obtiene la cadena de la sentencia SQL
     */
    QString getSql() const ;

    /**
     * Obtiene la cadena de la sentencia SQL
     */
    QString toString() const { return getSql(); }

    /**
     * Obtiene el numero de campos seleccionados, insertados o modificados segun el caso
     */
    int getNumeroCampos() const {
        return (m_eComando == Select ? m_strSelect : m_strListaCampos).count(',') + 1;
    }

    QString getSelect() const { return m_strSelect; }
    QString getFrom() const      { return m_strFrom; }
    QString getWhere() const  { return m_strWhere; }
    QString getGroup() const  { return m_strGroup; }
    QString getHaving() const { return m_strHaving; }
    QString getOrder() const  { return m_strOrder; }
    QString getFind() const   { return m_strFind; }

    void agregarSelect (const QString &str)    {
        m_eComando = Select;
        enlazarStrings (m_strSelect, ",\n\t", str);
    }
    void agregarFrom (const QString &str);
    void agregarLeftJoin (const QString &strTabla, const QString &strOn);
    void agregarRightJoin (const QString &strTabla, const QString &strOn);
    void agregarInnerJoin (const QString &strTabla, const QString &strOn);
    void agregarJoin (const QString &strTabla, const QString &strDireccion, const QString &strOn);

    void agregarWhere (const QString &str)      { agregarWhereAnd (str); }
    void agregarWhereAnd (const QString &str)    { enlazarStringsExpr (m_strWhere, " AND\n\t", str); }
    void agregarWhereOr (const QString &str)    { enlazarStringsExpr (m_strWhere, " OR\n\t", str); }
    void agregarGroup (const QString &str)      { enlazarStrings (m_strGroup, ",\n\t", str); }
    void agregarHaving (const QString &str)     { enlazarStringsExpr (m_strHaving, " AND\n\t", str); }
    void agregarOrder (const QString &str)      { enlazarStrings (m_strOrder, ",\n\t", str); }

    void setSelect (const QString &strCampos)       { m_strSelect = strCampos; m_eComando = Select; }
    void setFrom (const QString &strTabla)          { m_strFrom = strTabla; }
    void setWhere (const QString &strCondicion)     { m_strWhere = strCondicion; }
    void setGroup (const QString &strCampos)        { m_strGroup = strCampos; }
    void setHaving (const QString &strCondicion)    { m_strHaving = strCondicion; }
    void setOrder (const QString &strCampos)        { m_strOrder = strCampos; }

    void setInsert (const QString &str) { m_eComando = Insert; m_strTabla = str; }
    void setUpdate (const QString &str) { m_eComando = Update; m_strTabla = str; }
    void setDelete (const QString &str) { m_eComando = Delete; m_strTabla = str; }

    /**
     * Asigna un valor a un campo tipo cadena en sentencias insert y update
     */
    void asignar (QString strCampo, QString strValor);

    /**
     * Asigna un valor a un campo tipo entero en sentencias insert y update
     */
    void asignar (QString strCampo, int nValor) { asignar (strCampo, (qint64) nValor); }

    /**
     * Asigna un valor a un campo tipo entero de 64 bits en sentencias insert y update
     */
    void asignar (QString strCampo, qint64 nValor);

    /**
     * Asigna un valor a un campo tipo entero de 64 bits sin signo en sentencias insert y update
     */
    void asignar (QString strCampo, quint64 nValor);

    /**
     * Asigna un valor a un campo tipo real en sentencias insert y update
     */
    void asignar (QString strCampo, float dblValor) { asignar (strCampo, (double) dblValor); }

    /**
     * Asigna un valor a un campo tipo real doble en sentencias insert y update
     */
    void asignar (QString strCampo, double dblValor);

    /**
     * Asigna un valor a un campo tipo fecha y hora en sentencias insert y update
     */
    void asignar (QString strCampo, QDateTime dtValor);

    /**
     * Asigna un valor a un campo tipo fecha y hora en sentencias insert y update
     */
    void asignar(QString strCampo, QDate dtValor);

    /**
     * Asigna un valor a un campo tipo booleano en sentencias insert y update
     */
    void asignar (QString strCampo, bool bValor);

    /**
     * Asigna un valor nulo a un campo en sentencias insert y update
     */
    void asignarNull (QString strCampo);

    /**
     * Limpia los valores asignados en la sentencia
     */
    void limpiarValores();

    /**
     * Asigna un valor en formato SQL a un campo en sentencias insert y update
     */
    void asignarValorSql (QString strCampo, QString strValorSql);


private:
    static void enlazarStrings (QString& strExistente, QString strSeparador, QString strNuevo);
    static void enlazarStringsExpr (QString& strExistente, QString strSeparador, QString strNuevo);
};

#endif // SENTENCIASql_H
